package com.strongbj.iot.devices.guis.request.handle;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.strongbj.core.message.IMessageHandle;
import com.strongbj.core.util.ByteUtil;
import com.strongbj.iot.devices.guis.message.GUISOSMessageFactory;
import com.strongbj.iot.devices.guis.message.MQMessageOfGUIS;
import com.strongbj.iot.devices.guis.request.entity.LightCommandEntity;
import com.strongbj.iot.devices.guis.request.entity.LightCommandEntity.LightCommand;
import com.strongbj.iot.devices.guis.respnose.common.GuisCommonEntity;
import com.strongbj.iot.devices.guis.respnose.handle.GUISResponseHandleContext;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
/**
 * 点亮彩灯的接口   
 * @author 25969
 *
 */
public class ControlOpenColorLedTwinkleHandle implements IMessageHandle<MQMessageOfGUIS, Object> {

	private final static int MAX_U_SIZE = 54; // 最大U位数量
//	private TopicSender topicSender = (TopicSender) ContextUtils.getBean("topicSender");
	private static Logger logger = LogManager.getLogger(ControlOpenLedTwinkleHandle.class.getName());
	private final static String ACTION_CODE = "reader032"; // MQ中判断消息类型的标识符
	private final static byte command = (byte) 0x23;
	private GUISOSMessageFactory gUISOSMessageFactory = new GUISOSMessageFactory();
//	private static SimpleDateFormat df = null;
	private LightCommandEntity lightCommand = null;

	@Override
	public boolean isHandle(MQMessageOfGUIS t) {
		if (t.getActioncode().equals(ACTION_CODE)) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public Object handle(ChannelHandlerContext ctx, MQMessageOfGUIS t) {
		logger.info("GUIS 收到MQ发来的“向机柜发送亮灭【彩】灯的指令” json={}", JSON.toJSONString(t));
		lightCommand = ((JSONObject) t.getAwsPostdata()).toJavaObject(LightCommandEntity.class);
		this.messageDataToBytes(lightCommand, ctx, t.getTimeStamp());
		return null;
	}

	// 此处加一备注： 2018/2/5 和唐哥联调，对硬件测试，记录一些 采集的优化方案：
	/*
	 * 1.如果我判断设备已经掉线，这时我直接向上发送接口返回设备错误，不向下发了； 2.相对一个设备，每个指令下发间隔时间大于1秒；
	 * 加不了----要保证这个，你是不是得加队列，如果加个线程再去队列中轮询取消息，程序性能？ 硬件改
	 * 3.发送指令，设备没有反馈或返回失败，我间隔1秒继续发送，不超过3-5次，超过停止，向上返回错误。
	 * 加不了---考虑到有1秒内连发多次点灯指令，硬件只能给我返回一次反馈这种情况，我判断，再重发，加这么多算法肯定出bug？ 返回给上层处理
	 * 4.发送点亮指令时，对于业务系统没有指向的U位，作为自动填充数据放到包中，（FEFEFE）组成长报发送
	 * 5.我2分钟之内没收到你的心跳包，这时我直接向上发送接口返回设备错误； 6.标签号小写 涛哥说 7.IP HID 对应关系 加上
	 */
	/**
	 * 解析并下发数据给下位机 2018/2/5 追加解决方案4
	 * 发送点亮指令时，对于业务系统没有指向的U位，作为自动填充数据放到包中，（FEFEFE）组成长报发送 对下面的方法进行修改
	 * 
	 * @param lightCommand
	 */
	private void messageDataToBytes(LightCommandEntity lightCommand, ChannelHandlerContext ctx, long timeStamp) {
		for (LightCommandEntity.DevAddr devAddr : lightCommand.getDevAddrList()) {
			String devAddrCode = devAddr.getDevAddrCode(); // 主机编号
			// String timeStamp = String.valueOf(System.currentTimeMillis());
			byte[] bTimeStamp = new byte[8];
			bTimeStamp = ByteUtil.longToBytes(timeStamp);
			byte[] lightComByte = new byte[8 + MAX_U_SIZE * 4]; // 装数据的byte数组，由于发送整包，4*54=216；
			System.arraycopy(bTimeStamp, 0, lightComByte, 0, bTimeStamp.length);

			for (int j = 8; j < lightComByte.length; j++) {
				if ((j - 8) % 4 == 0) {
					lightComByte[j] = (byte) ((j - 8) / 4 + 1);
				} else {
					lightComByte[j] = (byte) 254;
				}
			}

			for (LightCommand lightCom : devAddr.getLightCommandList()) {
				int onTime = lightCom.getOnTime();
				int offTime = lightCom.getOffTime();
				int loopCount = lightCom.getLoopCount();
				int u = lightCom.getU();
				int color = lightCom.getColor();   //灯颜色
				int luminance = lightCom.getLuminance();  //灯亮度
				/*3BIT 颜色（0=灭 1=红 2=绿 3=蓝 4=黄 5=紫 6=白 7=定制）
				5BIT(二极管亮的延时默认单位100ms)+//这个=0就是灭
				3BIT 亮度（0--7）8个级别的亮度，通常3以上才好用。
				5BIT (二极管灭的延时默认单位100ms)+//这个=0就是常亮
*/
				//如上提示，需将16个bit转换为2byte
				byte secondByte = getByteByBit(color,onTime);
				byte threeByte = getByteByBit(luminance,offTime);
				if (u > MAX_U_SIZE)
					continue;
				// customSendUCollection.add(u);
				// 因为每个U占4个字节，此处根据U位号往 byte数组中填充对应位置的数据
				lightComByte[8 + 4 * (u - 1)] = (byte) u;
				lightComByte[8 + 4 * (u - 1) + 1] = (byte) secondByte;
				lightComByte[8 + 4 * (u - 1) + 2] = (byte) threeByte;
				lightComByte[8 + 4 * (u - 1) + 3] = (byte) loopCount;
			}

			byte[] bHostAddress = new byte[3]; // 接受主机编号的临时byte数组
			byte[] datas = gUISOSMessageFactory.createGUISOSMessage(
					ByteUtil.hexStringToBytes(devAddrCode, bHostAddress, 0), command, lightComByte);
			// byte[] datas =
			// gUISOSMessageFactory.createGUISOSMessage(ByteUtil.hexStringToBytes(devAddrCode,dest,0),
			// command, lightComByte);//记得注释这个
			// 打印
			// System.out.println("ByteUtil.byteArrToHexString(datas) " +
			// ByteUtil.byteArrToHexString(datas));
			ByteBuf bs = Unpooled.copiedBuffer(datas);
			// 根据HID找到对应的IP
			GuisCommonEntity guis = GuisCommonEntity.getInstance();
			//-------------------
		/*	NewReaderResponseHandleContext.channels.writeAndFlush(bs);
			logger.info("{} 点【彩】灯命令writeAndFlush写入完成 data={}", devAddrCode, ByteUtil.byteArrToHexString(datas));*/
			//---------------------------
			if (guis.getIpByHid.containsKey(devAddrCode)) {
				Channel channel = GUISResponseHandleContext.channels.find(guis.getIpByHid.get(devAddrCode));
				if (channel.isWritable()) {
					channel.writeAndFlush(bs);
					logger.info("{} 点【彩】灯命令writeAndFlush写入完成 data={}", devAddrCode, ByteUtil.byteArrToHexString(datas));
				} else {
					logger.info("{} 点【彩】灯命令不可写入 isOpen={} isActive={}    isWritable={} ", devAddrCode, channel.isOpen(),
							channel.isActive(), channel.isWritable());
				}
			} else {
				logger.info("{} 点【彩】灯命令写入失败，没有查找到指定的channelId, devAddrCode={}", devAddrCode, devAddrCode);
			}

			guis.put(timeStamp, System.currentTimeMillis(), true); // 向 lightReturnMap 添加 元素
			guis.putDevByTimeStamp(timeStamp, devAddrCode);
			// openASendLightAnswerListener(timeStamp);

			bTimeStamp = null;
			lightComByte = null;
			bHostAddress = null;
			datas = null;
		}

	}
/**
 * 将8个bit转换为1byte
 * @return
 */
	private  byte getByteByBit(int param1,int param2) {
/*		 StringBuffer sbLed = new StringBuffer();
		 sbLed.append(Integer.toBinaryString(param1))
			.append(Integer.toBinaryString(param2)).toString();
		 byte led = Integer.valueOf(sbLed.toString(),2).byteValue();
		 System.out.print("测试--"+byteToBit(led)+"          /r/n");
		return led;*/
		 byte fixedPart2 = (byte) ((0 & 0x0f) | (param1<<5));	 
	     fixedPart2 = (byte) (fixedPart2 | (param2<<0));
	//	 System.out.println("12  "+byteToBit(fixedPart2) );
		 return fixedPart2;
	 }
	
	public  String byteToBit(byte by) {
		StringBuffer sb = new StringBuffer();
		sb.append((by>>7)&0x1)
		.append((by>>6)&0x1)
		.append((by>>5)&0x1)
		.append((by>>4)&0x1)
		.append((by>>3)&0x1)
		.append((by>>2)&0x1)
		.append((by>>1)&0x1)
		.append((by>>0)&0x1);
		return sb.toString();
	}
	
	/**
	 * byte 给 每个bit赋值
	 * @param args
	 */
/*	public static void main(String args[]) {

		StringBuffer sbLed = new StringBuffer();
		 System.out.println("11          "+sbLed.append(Integer.toBinaryString(3)).toString());
		 System.out.println("12           "+Integer.valueOf(sbLed.toString(),2));
		 byte fixedPart2 = (byte) ((0 & 0x0f) | (3<<5));
		 
	 fixedPart2 = (byte) (fixedPart2 | (10<<0));
		 System.out.println("12  "+byteToBit(fixedPart2) );
	}*/



}
